import { NavigateFunction, NavigateOptions, To } from "react-router-dom";
import type { IAppContext } from "../Components/Provider";
import { Observe } from "elmer-common";
import { IServiceApi } from "../../Service";
import { MicroApp } from "./MicroApp";
import { createMicroAppProvider, useMicroApp } from "../Components/MicroApp";
import { AppStore } from "../Store/AppStore";
import { Utils } from "./Utils";

interface IApplicationOption {
    navigateTo: NavigateFunction;
    appContext: IAppContext;
    service: IServiceApi;
    entry?: {
        default: string;
        pages?: string[];
    }
}

interface IApplicationEvent {
    onDeviceTypeChange: (type: AppView.IDeviceType) => void;
}

export class Application {
    public deviceType: AppView.IDeviceType = "Desktop";
    public serviceApi: IServiceApi;
    public store: AppStore;
    public utils: Utils;

    private observe: Observe<IApplicationEvent> = new Observe<IApplicationEvent>();
    private isDesktop: boolean = false;
    
    constructor(private option: IApplicationOption) {
        this.serviceApi = option.service;
        this.store = new AppStore();
        this.deviceDetect();
        this.utils = Utils.getInstance();
    }
    on<EventName extends keyof IApplicationEvent>(name: EventName, callback: IApplicationEvent[EventName]) {
        return this.observe.on(name, callback);
    }
    go(to: To, option?: NavigateOptions) {
        this.option.navigateTo(to, option);
    }
    /**
     * 根据页面的namespace和id获取对应的页面
     * @param namespace 
     * @param id 
     * @returns 
     */
    getPageById(namespace: string, id: string): AppView.IPageEx|undefined {
        if(this.option.appContext.config.pages[namespace]) {
            const findPage = this.option.appContext.config.pages[namespace].filter((v) => v.id == id)[0];
            if(findPage) {
                return {
                    ...findPage,
                    id: `${namespace}.${findPage.id}`
                }
            }
        }
    }
    /**
     * 根据页面的key获取对应的页面(example: 'namespace.pageId')
     * @param pageKey 
     * @returns 
     */
    getPage(pageKey: string): AppView.IPageEx|undefined {
        const pageKeyMatch = /^([a-z0-9_]+)\.([a-z0-9_]+)$/i.exec(pageKey);
        if(pageKeyMatch) {
            return this.getPageById(pageKeyMatch[1], pageKeyMatch[2]);
        }
    }
    /**
     * 跳转到指定页面
     * @param pageKey 页面key
     * @param option 可选参数
     */
    goto(pageKey: string, option?: AppView.IApplicationGotoOption) {
        const page = this.getPage(pageKey);
        if(page) {
            this.option.navigateTo({
                pathname: page.pathname,
                hash: option?.hash,
                search: option?.search
            }, {
                state: option?.state,
                replace: option?.replace
            });
        } else {
            throw new Error(`Can not find the target page informaton.(${pageKey})`);
        }
    }
    getPageByPath(pathname: string): AppView.IPageEx | undefined {
        for(const namespace of Object.keys(this.option.appContext.config.pages)) {
            const namespaceData = this.option.appContext.config.pages[namespace];
            const urlPrefix = (namespaceData as any)["urlPrefix"];
            if(pathname.startsWith(urlPrefix)) {
                for(const page of namespaceData) {
                    const pagePathName = page.pathname || "";
                    if(pagePathName.startsWith(pathname)) {
                        return {...page};
                    }
                }
            }
        }
    }
    /**
     * 进入到首页，默认admin.main页面
     * @param state 传递参数
     */
    goHome(state?: any) {
        this.goto(this.option.entry?.default ?? "admin.main", {
            state
        });
    }
    /**
     * 销毁application
     */
    destory(): void {
        this.unlinkResizeEvent();
    }
    /**
     * 创建微应用
     * @param options 
     * @returns 
     */
    createMicroApp(options: AppView.IMicroAppOption): { Provider: React.ComponentType<any>, useMicroApp: () => MicroApp } {
        const Provider = createMicroAppProvider(options);
        return {
            Provider,
            useMicroApp
        };
    }
    /**
     * 根据navigator.useUserAgent判断设备类型
     */
    private deviceDetect(): void {
        const userAgent = navigator.userAgent;
        const isAndroid = userAgent.indexOf('Android') > -1 || userAgent.indexOf('Adr') > -1;
        const isIOS = !!userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
        const isMobile = isAndroid || isIOS;
        const isIPAD = !isMobile && /Android|iPad/i.test(userAgent);
        const screenPercent = window.innerWidth / window.innerHeight;
        if(isMobile) {
            this.deviceType = "Mobile";
        } else if (isIPAD) {
            this.deviceType = "iPad";
        } else {
            this.isDesktop = true;
            this.deviceType = screenPercent < .45 ? "Mobile" : "Desktop";
        }
        this.initResizeEvent();
    }
    private initResizeEvent(): void {
        window.addEventListener("resize", this.resize.bind(this));
    }
    private unlinkResizeEvent(): void {
        window.removeEventListener("resize", this.resize.bind(this));
    }
    private resize(): void {
        const cWidth = window.innerWidth;
        const cHeight = window.innerHeight;
        if(this.isDesktop) {
            const currentDeviceType = cWidth/cHeight < .45 ? "Mobile" : "Desktop";
            if(currentDeviceType !== this.deviceType) {
                this.deviceType = currentDeviceType;
                this.observe.emit("onDeviceTypeChange", currentDeviceType);
            }
        }
    }
}